import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectModel } from 'nest-typegoose';
import { ReturnModelType } from '@typegoose/typegoose';
import { CreateWebmenuDto } from './dto/create-webmenu.dto';
import { UpdateWebmenuDto } from './dto/update-webmenu.dto';
import { WebMenu } from '@libs/db/models/webmenu.model';
import { createWebPage, deleteWebPage, pageTemplate } from "utils";
import { ConfigurationService } from '../configuration/configuration.service';
import { WebbaseService } from 'src/webbase/webbase.service';

@Injectable()
export class WebmenusService {
  constructor(
    @InjectModel(WebMenu) private webMenuModel: ReturnModelType<typeof WebMenu>,
    private configurationService: ConfigurationService,
    private webbaseService: WebbaseService
  ) { }

  /**
   * 生成唯一的菜单编码
   * @returns 生成的编码字符串
   */
  private generateMenuCode(): string {
    const timestamp = Date.now().toString(36); // 时间戳转36进制
    const randomStr = Math.random().toString(36).substring(2, 8); // 随机字符串
    return `MENU_${timestamp}_${randomStr}`.toUpperCase();
  }

  /**
   * 创建新的Web菜单
   * @param createWebmenuDto 创建菜单的数据传输对象
   * @returns 创建的菜单对象
   */
  async create(createWebmenuDto: CreateWebmenuDto): Promise<WebMenu> {
    // 自动生成菜单编码
    let generatedCode = this.generateMenuCode();
    // 确保生成的编码唯一（极小概率重复时重新生成）
    let attempts = 0;
    while (attempts < 5) {
      const existingMenu = await this.webMenuModel.findOne({ code: generatedCode }).exec();
      if (!existingMenu) {
        break;
      }
      generatedCode = this.generateMenuCode();
      attempts++;
    }

    // 设置自动生成的编码
    createWebmenuDto.code = generatedCode;
    const createdWebMenu = new this.webMenuModel(createWebmenuDto);
    let createResult = { status: true, msg: '无需创建页面' };
    // 如果是外部链接，则直接返回,优先级最高
    if (createWebmenuDto.isOutLink === 1) {
      return createdWebMenu.save();
    }
    // 如果是页面或列表，那么需要创建
    if (['page', 'detail'].includes(createWebmenuDto.modelType)) {
      // 获取系统配置中的站点模板
      const pageContent = await this.generatePageContent(createWebmenuDto.modelType, createWebmenuDto.code, createWebmenuDto.detailTplId);
      createResult = createWebPage(createWebmenuDto.link, createWebmenuDto.modelType, pageContent);
    } else if (createWebmenuDto.modelType === 'list') {
      const pageContent = await this.generatePageContent(createWebmenuDto.modelType, createWebmenuDto.code, createWebmenuDto.listTplId);
      const detailContent = await this.generatePageContent(createWebmenuDto.modelType, createWebmenuDto.code, createWebmenuDto.detailTplId);
      createResult = createWebPage(createWebmenuDto.link, createWebmenuDto.modelType, pageContent, detailContent);
    }
    if (createResult.status) {
      return createdWebMenu.save();
    } else {
      throw new BadRequestException(`创建页面失败: ${createResult.msg}`);
    }
  }

  /**
   * 生成页面内容
   * @param modelType 模型类型（来源：用户输入）
   * @param modelId 模型ID（来源：用户输入）
   * @param tplId 模板ID（来源：用户输入）
   * @returns 生成的页面内容
   */
  async generatePageContent(modelType: string, menuCode: string, tplId: string): Promise<string> {
    const systemConfig = await this.configurationService.getSystemConfig();
    const siteTemplate = systemConfig.siteInfo.siteTemplate;
    let pageContent = "";
    const templateName = await this.webbaseService.findOneTemplates(tplId);
    console.log(templateName.bindFileName, "绑定的文件名称");

    // 替换modelType（确定是否为动态加载）、设置模板code（用户据获取页面数据）、模板为当前系统设置的模板；
    pageContent = pageTemplate.replace(/\$pageType/g, modelType).replace(/\$pageCode/g, menuCode).replace(/\$component/g, templateName.bindFileName + ".vue");
    return pageContent;
  }

  /**
   * 获取所有Web菜单列表
   * @param page 页码，默认为1
   * @param limit 每页数量，默认为10
   * @param status 菜单状态筛选，可选
   * @param name 菜单名称模糊查询，可选
   * @param modelType 菜单类型筛选，可选
   * @returns 菜单列表和总数
   */
  async findAll(page: number = 1, limit: number = 1000, status?: number, name?: string, modelType?: string) {
    const skip = (page - 1) * limit;
    const filter: any = {};

    if (status !== undefined) {
      filter.status = status;
    }

    if (name) {
      filter.name = { $regex: name, $options: 'i' }; // 模糊查询，忽略大小写
    }

    if (modelType) {
      filter.modelType = modelType;
    }

    const [data, total] = await Promise.all([
      this.webMenuModel.find(filter).skip(skip).limit(limit).sort({ sort: 1, createdAt: -1 }).exec(),
      this.webMenuModel.countDocuments(filter).exec(),
    ]);

    return {
      data,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 根据ID获取单个Web菜单
   * @param id 菜单ID
   * @returns 菜单对象
   */
  async findOne(id: string): Promise<WebMenu> {
    const webMenu = await this.webMenuModel.findById(id).exec();
    if (!webMenu) {
      throw new NotFoundException(`Web菜单 ID ${id} 未找到`);
    }
    return webMenu;
  }

  /**
   * 根据菜单编码获取Web菜单
   * @param code 菜单编码
   * @returns 菜单对象
   */
  async findByCode(code: string): Promise<WebMenu> {
    const webMenu = await this.webMenuModel.findOne({ code }).exec();
    if (!webMenu) {
      throw new NotFoundException(`菜单编码 ${code} 未找到`);
    }
    return webMenu;
  }

  /**
   * 根据父菜单编码获取子菜单列表
   * @param parentCode 父菜单编码
   * @returns 子菜单列表
   */
  /**
   * 根据父节点编码获取树形菜单结构
   * @param parentCode 父节点编码
   * @returns 以指定父节点为根的树形菜单结构
   */
  async findByParentCode(parentCode: string): Promise<any[]> {
    // 查询所有状态为1的菜单
    const allMenus = await this.webMenuModel.find({ status: 1 }).sort({ sort: 1, parentCode: 1, code: 1 }).exec();
    // 以传入的parentCode为根节点构建树形结构
    return this.buildMenuTreeByParent(allMenus, parentCode);
  }

  /**
   * 根据模型类型获取菜单列表
   * @param modelType 模型类型（来源：用户输入）
   * @param page 页码，默认为1
   * @param limit 每页数量，默认为10
   * @param status 菜单状态筛选，可选
   * @returns 菜单列表和总数
   */
  async findByModelType(modelType: string, page: number = 1, limit: number = 10, status?: number) {
    const skip = (page - 1) * limit;
    const filter: any = { modelType };

    if (status !== undefined) {
      filter.status = status;
    }

    const [rows, total] = await Promise.all([
      this.webMenuModel.find(filter).sort({ sort: 1, createdAt: -1 }).exec(),
      this.webMenuModel.countDocuments(filter).exec(),
    ]);

    return {
      rows,
      total,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 根据模型类型获取所有菜单列表（不分页）
   * @param modelType 模型类型（来源：用户输入）
   * @param status 菜单状态筛选，可选
   * @returns 菜单列表
   */
  async findAllByModelType(modelType: string, status?: number): Promise<WebMenu[]> {
    const filter: any = { modelType };

    if (status !== undefined) {
      filter.status = status;
    }

    return this.webMenuModel.find(filter).sort({ sort: 1, createdAt: -1 }).exec();
  }

  /**
   * 根据模型ID获取菜单
   * @param modelId 模型ID（来源：用户输入）
   * @returns 菜单对象
   */
  async findByModelId(modelId: string): Promise<WebMenu[]> {
    const webMenu = await this.webMenuModel.find({ modelId }).exec();
    if (!webMenu) {
      throw new NotFoundException(`模型ID ${modelId} 对应的菜单未找到`);
    }
    return webMenu;
  }

  /**
   * 获取菜单树形结构
   * @returns 树形菜单结构
   */
  async getMenuTree(): Promise<any[]> {
    const allMenus = await this.webMenuModel.find({ status: 1 }).sort({ sort: 1, parentCode: 1, code: 1 }).exec();
    return this.buildMenuTree(allMenus);
  }

  /**
   * 以指定父节点为根构建菜单树形结构
   * @param menus 扁平化菜单数组
   * @param rootParentCode 根节点的父编码
   * @returns 以指定父节点为根的树形菜单结构
   */
  private buildMenuTreeByParent(menus: WebMenu[], rootParentCode: string): any[] {
    /**
     * 递归构建树形结构
     * @param parentCode 父菜单编码
     * @returns 当前层级的菜单数组
     */
    const buildTreeRecursive = (parentCode: string): any[] => {
      // 筛选出当前父节点下的所有子节点
      const children = menus
        .filter(menu => menu.parentCode === parentCode && menu.code !== parentCode)
        .sort((a, b) => (a.sort || 0) - (b.sort || 0)); // 按sort字段排序

      // 递归构建每个子节点的children
      return children.map(menu => {
        const childNodes = buildTreeRecursive(menu.code);
        return {
          // @ts-ignore
          ...menu.toObject(),
          children: childNodes.length > 0 ? childNodes : []
        };
      });
    };

    // 以传入的rootParentCode为根节点构建树形结构
    return buildTreeRecursive(rootParentCode);
  }

  /**
   * 构建菜单树形结构
   * @param menus 扁平化菜单数组
   * @returns 树形菜单结构
   */
  private buildMenuTree(menus: WebMenu[]): any[] {

    // 找出所有的parentCode值
    const allParentCodes = new Set(menus.map(menu => menu.parentCode).filter(Boolean));
    // 找出所有的code值
    const allCodes = new Set(menus.map(menu => menu.code));

    // 根节点：parentCode不在任何菜单的code中，或者parentCode为空/null/undefined
    const rootMenus = menus.filter(menu => {
      return !menu.parentCode ||
        menu.parentCode === '' ||
        menu.parentCode === '0' ||
        menu.parentCode === 'root' ||
        !allCodes.has(menu.parentCode);
    });

    /**
     * 递归构建树形结构
     * @param parentCode 父菜单编码
     * @returns 当前层级的菜单数组
     */
    const buildTreeRecursive = (parentCode: string): any[] => {
      // 筛选出当前父节点下的所有子节点
      const children = menus
        .filter(menu => menu.parentCode === parentCode && menu.code !== parentCode)
        .sort((a, b) => (a.sort || 0) - (b.sort || 0)); // 按sort字段排序

      // 递归构建每个子节点的children
      return children.map(menu => {
        const childNodes = buildTreeRecursive(menu.code);
        return {
          // @ts-ignore
          ...menu.toObject(),
          children: childNodes.length > 0 ? childNodes : []
        };
      });
    };

    // 构建根节点的树形结构
    const result = rootMenus.map(menu => {
      const childNodes = buildTreeRecursive(menu.code);
      return {
        // @ts-ignore
        ...menu.toObject(),
        children: childNodes.length > 0 ? childNodes : []
      };
    }).sort((a, b) => (a.sort || 0) - (b.sort || 0));
    return result;
  }



  /**
   * 更新Web菜单
   * @param id 菜单ID
   * @param updateWebmenuDto 更新菜单的数据传输对象
   * @returns 更新后的菜单对象
   */
  async update(id: string, updateWebmenuDto: UpdateWebmenuDto): Promise<WebMenu> {
    console.log('更新菜单，数据:', updateWebmenuDto);

    // 执行更新操作，返回更新后的数据
    const updatedWebMenu = await this.webMenuModel
      .findByIdAndUpdate(id, updateWebmenuDto, { new: true })
      .exec();

    if (!updatedWebMenu) {
      throw new NotFoundException(`Web菜单 ID ${id} 未找到`);
    }

    return updatedWebMenu;
  }

  /**
   * 删除Web菜单
   * @param id 菜单ID（来源：控制器传入）
   * @returns 删除结果消息
   */
  async remove(id: string): Promise<{ message: string }> {
    // 先查找要删除的菜单
    const menuToDelete = await this.webMenuModel.findById(id).exec();

    if (!menuToDelete) {
      throw new NotFoundException(`Web菜单 ID ${id} 未找到`);
    }

    // 检查是否存在子菜单
    const childMenus = await this.webMenuModel.find({ parentCode: menuToDelete.code }).exec();

    if (childMenus.length > 0) {
      throw new BadRequestException(`无法删除菜单 "${menuToDelete.name}"，因为存在 ${childMenus.length} 个子菜单`);
    }

    // 如果菜单有页面文件，先删除页面文件
    if (menuToDelete.link && ['page', 'list'].includes(menuToDelete.modelType)) {
      const deleteResult = deleteWebPage(menuToDelete.link, menuToDelete.modelType);
      console.log('页面删除结果:', deleteResult);

      // 如果页面删除失败，抛出异常
      if (!deleteResult.status) {
        throw new BadRequestException(`删除页面文件失败: ${deleteResult.msg}`);
      }
    }

    // 执行删除操作
    const result = await this.webMenuModel.findByIdAndDelete(id).exec();

    return { message: `Web菜单 "${menuToDelete.name}" 和相关页面文件已成功删除` };
  }

  /**
   * 批量删除Web菜单
   * @param ids 菜单ID数组
   * @returns 删除结果
   */
  async removeMany(ids: string[]): Promise<{ message: string; deletedCount: number }> {
    const result = await this.webMenuModel.deleteMany({ _id: { $in: ids } }).exec();

    return {
      message: `成功删除 ${result.deletedCount} 个Web菜单`,
      deletedCount: result.deletedCount
    };
  }

  /**
   * 更新菜单状态
   * @param id 菜单ID
   * @param status 新状态
   * @returns 更新后的菜单对象
   */
  async updateStatus(id: string, status: number): Promise<WebMenu> {
    const updatedWebMenu = await this.webMenuModel
      .findByIdAndUpdate(id, { status }, { new: true })
      .exec();

    if (!updatedWebMenu) {
      throw new NotFoundException(`Web菜单 ID ${id} 未找到`);
    }

    return updatedWebMenu;
  }
}